﻿using RndMaterialDisposalService.AutoMapperProfile;
using RndMaterialDisposalService.Extensions;
using RndMaterialDisposalService.Repository;
using RndMaterialDisposalService.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Serilog;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Microsoft.AspNetCore.Authorization;
using Serilog.Events;
using System.Collections.ObjectModel;
using System.Data;
using Serilog.Sinks.MSSqlServer;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

var configuration = builder.Configuration;

builder.Services.AddControllers(cfg => {
    cfg.Filters.Add<ApiResultResponseFilter>();
    //cfg.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes=true; //可以为空
}).AddJsonOptions(opt => {
    opt.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
    opt.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    opt.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
    opt.JsonSerializerOptions.Converters.Add(new DateTimeConverterProvider());
    opt.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});

//配置数据库
builder.Services.AddDbContext<WorkflowCommonDataContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("WorkflowCommonData"));
});
builder.Services.AddDbContext<RNDBVDataContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("RNDBVData"));
});
builder.Services.AddDbContext<AssetsManagementContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("AssetsManagementData"));
});
builder.Services.AddDbContext<EDPMiddleContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("EmployeeInforData"));
});

builder.Services.AddDbContext<UserBaseInforDataContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("UserBaseInforData"));
    if (builder.Environment.EnvironmentName == "Uat")
    {
        options.ReplaceService<IQueryTranslationPostprocessorFactory, SqlServer2008QueryTranslationPostprocessorFactory>();
    }
});
builder.Services.AddDbContext<EDPPlatformContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("EDPPlatformData"));
});
builder.Services.AddDbContext<EDPApplicationContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("EDPApplicationData"));
});
builder.Services.AddDbContext<K2Context>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("K2ServerConn"));
});

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    //swagger的host信息
    options.DocumentFilter<SwaggerHostInfo>();
    //swagger注释
    var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);
    options.IncludeXmlComments(Path.Combine(basePath, "RndMaterialDisposal.xml"),true);
});

//自动注入Services
builder.Services.AddAutoInject();
builder.Services.AddScoped(typeof(EFExtension));
//builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();  //使用了自动注入
//builder.Services.AddSingleton<IAuthorizationPolicyProvider, TestAuthorizationPolicyProvider>();//使用了自动注入

builder.Services.AddAutoMapper(cfg => {
    cfg.AddProfile<CapitalTransferReportProfile>();
    cfg.AddProfile<CapitalScrapReportProfile>();
});

builder.Services.AddMemoryCache();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true, //是否验证Issuer
            ValidIssuer = configuration["Jwt:Issuer"], //发行人Issuer
            ValidateAudience = true, //是否验证Audience
            ValidAudience = configuration["Jwt:Audience"], //订阅人Audience
            ValidateIssuerSigningKey = true, //是否验证SecurityKey
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"])), //SecurityKey
            ValidateLifetime = true, //是否验证失效时间
            ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值，解决服务器端时间不同步问题（秒）
            RequireExpirationTime = true,
        };
    });

//注册授权服务
builder.Services.AddAuthorization(options =>
{
    //policy2 要求用户拥有一个 Claim，其 ClaimType 值为 EmployeeNumber，且其 ClaimValue 值为1、2、3、4 或 5。
    options.AddPolicy("policy1", policy => policy.RequireClaim("Username", "Admin"));

    //测试策略  动态加载
    //options.AddPolicy(UserPermission.User, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.User)));
    //options.AddPolicy(UserPermission.UserList, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserList)));
    //options.AddPolicy(UserPermission.UserCreate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserCreate)));
    //options.AddPolicy(UserPermission.UserUpdate, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserUpdate)));
    //options.AddPolicy(UserPermission.UserDelete, policy => policy.AddRequirements(new PermissionAuthorizationRequirement(UserPermission.UserDelete)));
});

//添加跨域设置
builder.Services.AddCors(cor =>
{
    cor.AddPolicy("Cors", policy =>
    {
        //policy.WithOrigins("http://mobileuat.vertivco.com.cn", "http://mobileuat.vertivco.com.cn:8001", "http://mobileuat.vertivco.com.cn:8002")
        policy.AllowAnyOrigin()
        .AllowAnyHeader()
        .AllowAnyMethod();
    });
});

//日志路径
string serilogVerbose = @$"{System.Environment.CurrentDirectory}\Log\Verbose.log";
string serilogDebug = @$"{System.Environment.CurrentDirectory}\Log\Debug.log";
string serilogInfo = @$"{System.Environment.CurrentDirectory}\Log\Info.log";
string serilogWarn = @$"{System.Environment.CurrentDirectory}\Log\Warning.log";
string serilogError = @$"{System.Environment.CurrentDirectory}\Log\Error.log";
string serilogFatal = @$"{System.Environment.CurrentDirectory}\Log\Fatal.log";
//日志输出模版
string serilogOutputTemplate = "{NewLine}时间:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}日志等级:{Level}{NewLine}所在类:{SourceContext}{NewLine}日志信息:{Message}{NewLine}{Exception}";

var columnOptions = new ColumnOptions();
columnOptions.Store.Remove(StandardColumn.MessageTemplate);//删除标准列
columnOptions.Properties.ExcludeAdditionalProperties = true;//排除已经自定义列的数据
columnOptions.AdditionalColumns = new Collection<SqlColumn>//添加自定义列
    {
        new SqlColumn { DataType = SqlDbType.NVarChar, DataLength = 32, ColumnName = "IP" }
    };

//配置日志Serilog
builder.Host.UseSerilog((context, logger) =>
{
    //如果是配置的取消注释。配置文件和代码其实可以配合使用的，需要尝试。
    //logger.ReadFrom.Configuration(context.Configuration);  

    //最小记录日志级别设置。最小记录日志级别 （Verbose，Debug，Information，Warning，Error，Fatal）
    logger.MinimumLevel.Debug().MinimumLevel.Override("Microsoft", LogEventLevel.Warning).MinimumLevel.Override("System", LogEventLevel.Warning);
    logger.Enrich.FromLogContext();
    // 输出到Console控制台
    logger.WriteTo.Console();  
    // 输出到配置的文件日志目录
    logger.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Verbose).WriteTo.Async(a => a.File(serilogVerbose, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)))
        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.Async(a => a.File(serilogDebug, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)))
        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.Async(a => a.File(serilogInfo, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)))
        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.Async(a => a.File(serilogWarn, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)))
        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.Async(a => a.File(serilogError, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)))
        .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.Async(a => a.File(serilogFatal, rollingInterval: RollingInterval.Day, outputTemplate: serilogOutputTemplate)));

    logger.WriteTo.MSSqlServer(
                   connectionString: configuration["ConnectionStrings:AssetsManagementData"],
                   tableName: "LogTable",
                   batchPostingLimit: 10,//批量插入数据库条数
                   period: TimeSpan.FromSeconds(5),//执行时间间隔
                   restrictedToMinimumLevel: LogEventLevel.Debug,
                   columnOptions: columnOptions,
    autoCreateSqlTable: true//自动创建表
               );




});

builder.Services.AddCoravelJob();

builder.Services.AddRazorPages(options =>
{

});

Console.WriteLine($"当前环境：{builder.Environment.EnvironmentName}");

var app = builder.Build();

//添加跨域设置
app.UseCors("Cors");

// Configure the HTTP request pipeline.
//if (app.Environment.IsDevelopment())
//{
app.UseSwagger(options =>
{
    options.SerializeAsV2 = true;
});
    app.UseSwaggerUI();
//}

//app.UseHttpsRedirection();

//app.UseQuartz();

app.UseCoravelJob();

app.MapRazorPages();

//认证
app.UseAuthentication();
//授权
app.UseAuthorization();

app.UseMiddleware<GlobalExceptionMiddleware>();

app.MapControllers();

app.UseMiddleware<ResponseMiddleware>();

app.Run();
